/***********************************************************
 *  File_Name  : XJField.h
 *  File_Path   :
 *  File_Encode : UTF8
 *  Description : Field Class
 *
 *  OS : Linux, UNIX
 *  LastVersion  : 20150115
 *
 *  Author      : LiXiujie(李秀杰)
 *  Date        : 2015-1-15
 *  Version     : 20150115
 *  Description :
 *
 *  Edit Author :
 *  Edit Date   :
 *  Version     :
 *  Description :
 *
 ***********************************************************/
#ifndef XJF_H_
#define XJF_H_

#include "XJEnv.h"

#include <string>
#include <vector>
#include <assert.h>
#include <iostream>
using namespace std;
namespace XJUtilClass {

typedef	int		XJT32I;
typedef	unsigned int XJT32U;

typedef	long long		XJT64I;
typedef	unsigned long long	XJT64U;

//#define  XJFSTRING_HEX  1
//#define XJF_JSON   1
//#define XJF_TUXEDO 1

#ifndef XJ_RET_SUCC
#define XJ_RET_SUCC 				0
#define XJ_RET_FAIL 				-1
#endif

#ifndef XJ_RET_F_HAS_PARENT
#define XJ_RET_F_HAS_PARENT			-10  // 已存在父节点
#define XJ_RET_F_NOT_PARENT			-11  // 不是一个父节点
#define XJ_RET_F_DEFF_PARENT		-12  // 不是同一个父节点
#define XJ_RET_F_IS_NULL			-13  // 空对象
#define XJ_RET_F_TYPE_INVALID		-14  // 无效类型
#define XJ_RET_F_INDEX_INVALID		-15  // 无效索引
#define XJ_RET_F_SIZE_ZERO			-16  // 大小为空
#define XJ_RET_F_MALLOC_NULL		-17  // 申请空间失败
#define XJ_RET_F_BUF_LEN_ERROR		-18  // BUF长度小或为0
#define XJ_RET_F_JSON_OBJECT_NULL	-19	 // JSON Object NULL
#define XJ_RET_F_JSON_TO_STR_NULL	-20	 // JSON Object TO STRING NULL
#endif

class XJFShort;
class XJFLong;
class XJFChar;
class XJFFloat;
class XJFDouble;
class XJFString;
class XJFCarray;
class XJFObject;
class XJFArray;
class XJFPTR;

class XJF {
public:
	enum XJF_TYPE{
		TYPE_SHORT=0,
		TYPE_LONG=1,
		TYPE_CHAR=2,
		TYPE_FLOAT=3,
		TYPE_DOUBLE=4,
		TYPE_STRING=5,
		TYPE_CARRAY=6,
		TYPE_PTR=7,
		TYPE_OBJECT=10,
		TYPE_ARRAY=11,
		TYPE_NULL=99
	};
protected:
	XJF(const string &strName, const char* pValue, const XJT32U &nLen=0, const enum XJF_TYPE nType=TYPE_NULL);
	XJF(const string &strName, enum XJF_TYPE nType);
public:
	static XJF *New(const string &strName, const char* pValue, const XJT32U &nLen=0, const enum XJF_TYPE nType=TYPE_NULL);
	static XJFObject *NewFObject(const string &strName);
	static XJFArray  *NewFArray(const string &strName);
	static XJFShort  *NewFShort(const string &strName, const unsigned short &sValue=0);
	static XJFLong   *NewFLong(const string &strName, const XJT32U &nValue=0);
	static XJFChar   *NewFChar(const string &strName, const unsigned char &chValue = 0);
	static XJFFloat  *NewFFloat(const string &strName, const float &fValue = 0.00);
	static XJFDouble *NewFDouble(const string &strName, const double &dValue = 0.00);
	static XJFString *NewFString(const string &strName, const string &strValue="");
	static XJFCarray *NewFCarray(const string &strName, const char* pValue, const XJT32U &nLen);
	static XJFPTR    *NewFPTR(const string &strName, const void* pValue);
	XJF *ToF(){
		return (XJF *)this;
	}
	XJFShort *ToFShort(){
		if(m_nType == TYPE_SHORT)return (XJFShort *)this;
		return NULL;
	}
	XJFLong *ToFLong(){
		if(m_nType == TYPE_LONG)return (XJFLong *)this;
		return NULL;
	}
	XJFChar *ToFChar(){
		if(m_nType == TYPE_CHAR)return (XJFChar *)this;
		return NULL;
	}
	XJFFloat *ToFFloat(){
		if(m_nType == TYPE_FLOAT)return (XJFFloat *)this;
		return NULL;
	}
	XJFDouble *ToFDouble(){
		if(m_nType == TYPE_DOUBLE)return (XJFDouble *)this;
		return NULL;
	}
	XJFString *ToFString(){
		if(m_nType == TYPE_STRING)return (XJFString *)this;
		return NULL;
	}
	XJFCarray *ToFCarray(){
		if(m_nType == TYPE_CARRAY)return (XJFCarray *)this;
		return NULL;
	}
	XJFObject *ToFObject(){
		if(m_nType == TYPE_OBJECT)return (XJFObject *)this;
		return NULL;
	}
	XJFArray *ToFArray(){
		if(m_nType == TYPE_ARRAY)return (XJFArray *)this;
		return NULL;
	}
	XJFPTR *ToFPTR(){
		if(m_nType == TYPE_PTR)return (XJFPTR *)this;
		return NULL;
	}
	virtual ~XJF();
public:
	/// Delete all the children of this node. Does not affect 'this'.
	void Clear();
	const string & SetName(const string &strName) {
		m_strName=strName;
		if(m_strName.size()>255){
			m_strName = m_strName.substr(0, 255);
		}
		return m_strName;
	}
	const string & GetName() const { return m_strName; }
	const XJT32U GetValueLen(const XJT32U &nIndex = 0);
	int GetValue(char* pValue, XJT32U &nLen,const XJT32U &nIndex = 0);
	int SetValue(const char* pValue, const XJT32U &nLen,const XJT32U &nIndex = 0);
	int DelValue(const XJT32U &nIndex = 0);
	const XJT32U GetValueCount(){
		return m_veValue.size();
	}
	const enum XJF_TYPE GetType() { return m_nType; }
	const enum XJF_TYPE SetType(const enum XJF_TYPE nType=TYPE_NULL){
		m_nType = nType;
		return m_nType;
	}
	XJF* Parent()							{ return m_pParent; }
	const XJF* Parent() const				{ return m_pParent; }
	const XJF* FirstChild()	const		{ return m_pFirstChild; }	///< The first child of this node. Will be null if there are no children.
	XJF* FirstChild()						{ return m_pFirstChild; }
	const XJF* LastChild() const			{ return m_pLastChild; }		/// The last child of this node. Will be null if there are no children.
	XJF* LastChild()						{ return m_pLastChild; }
	const XJF* PreviousSibling() const			{ return m_pPrev; }
	XJF* PreviousSibling()						{ return m_pPrev; }
	const XJF* NextSibling() const				{ return m_pNext; }
	XJF* NextSibling()							{ return m_pNext; }

	const XJF* FirstChild( const string &strName ) const;			///< The first child of this node with the matching 'strName'. Will be null if none found.
	/// The first child of this node with the matching 'strName'. Will be null if none found.
	XJF* FirstChild( const string &strName ) {
		// Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe)
		// call the method, cast the return back to non-const.
		return const_cast< XJF* > ((const_cast< const XJF* >(this))->FirstChild( strName ));
	}

	const XJF* LastChild( const string &strName ) const;			/// The last child of this node matching 'strName'. Will be null if there are no children.
	XJF* LastChild( const string &strName ) {
		return const_cast< XJF* > ((const_cast< const XJF* >(this))->LastChild( strName ));
	}

	/** An alternate way to walk the children of a node.
		One way to iterate over nodes is:
		@verbatim
			for( child = parent->FirstChild(); child; child = child->NextSibling() )
		@endverbatim

		IterateChildren does the same thing with the syntax:
		@verbatim
			child = 0;
			while( child = parent->IterateChildren( child ) )
		@endverbatim

		IterateChildren takes the previous child as input and finds
		the next one. If the previous child is null, it returns the
		first. IterateChildren will return null when done.
	*/
	const XJF* IterateChildren( const XJF* previous ) const;
	XJF* IterateChildren( const XJF* previous ) {
		return const_cast< XJF* >( (const_cast< const XJF* >(this))->IterateChildren( previous ) );
	}

	/// This flavor of IterateChildren searches for children with a particular 'strName'
	const XJF* IterateChildren( const string &strName, const XJF* previous ) const;
	XJF* IterateChildren( const string &strName, const XJF* previous ) {
		return const_cast< XJF* >( (const_cast< const XJF* >(this))->IterateChildren( strName, previous ) );
	}

	/// Navigate to a sibling node.
	const XJF* PreviousSibling( const string &strName ) const;
	XJF* PreviousSibling( const string &strName ) {
		return const_cast< XJF* >( (const_cast< const XJF* >(this))->PreviousSibling( strName ) );
	}

	/// Navigate to a sibling node with the given 'value'.
	const XJF* NextSibling( const string &strName ) const;
	XJF* NextSibling( const string &strName ) {
		return const_cast< XJF* >( (const_cast< const XJF* >(this))->NextSibling( strName ) );
	}
	/** Add a new node related to this. Adds a child past the LastChild.

		NOTE: the node to be added is passed by pointer, and will be
		henceforth owned (and deleted) by XJ. This method is efficient
		and avoids an extra copy, but should be used with care as it
		uses a different memory model than the other insert functions.
		return addThis

	*/
	XJF* InsertFirstChild( XJF* addThis );

	/** Add a new node related to this. Adds a child past the LastChild.

		NOTE: the node to be added is passed by pointer, and will be
		henceforth owned (and deleted) by XJ. This method is efficient
		and avoids an extra copy, but should be used with care as it
		uses a different memory model than the other insert functions.
		return addThis

	*/
	XJF* InsertLastChild( XJF* addThis );

	/** Add a new node related to this. Adds a child before the specified child.
		Returns a pointer to the addThis or NULL if an error occured.
	*/
	XJF* InsertBeforeChild( XJF* beforeThis, XJF* addThis );

	/** Add a new node related to this. Adds a child after the specified child.
		Returns a pointer to the addThis or NULL if an error occured.
	*/
	XJF* InsertAfterChild(  XJF* afterThis, XJF* addThis );

	/** Replace a child of this node.
	    Auto free replaceThis_old.
	 	Returns a pointer to the withThis_new or NULL if an error occured.
	*/
	XJF* ReplaceChild( XJF* replaceThis_old, XJF* withThis_new );

	/// Delete a child of this node.
	bool RemoveChild( XJF* removeThis );
	//  duplicate new XJF
	static	XJF* NewDuplicate(XJF* pF);
public:
	const XJT32U GetBufLen(const XJF* pF = NULL);
	int ToBuf(char *pBuf, XJT32U &nLen,const XJF* pF = NULL);
	static XJF *NewFromBuf(const char *pBuf,const XJT32U &nLen);
#ifdef XJF_JSON
	const XJT32U GetJsonLen(bool bJsonPretty = false, const XJF* pF = NULL);
	int ToJson(char *pJson, XJT32U &nLen, bool bJsonPretty = false, const XJF* pF = NULL);
	static XJF *NewFromJson(const char *pJson);
	string ToJson(bool bJsonPretty = false, const XJF* pF = NULL);
#endif
#ifdef XJF_TUXEDO
	static XJFObject *NewFromFML(void* pFMLData, bool bToFldName = true);
	int ToFML(void* pFMLData, const XJF* pF = NULL);
#endif
	static const int GetERRNO(){int nERRNO =m_nERRNO;m_nERRNO=0;return nERRNO;}
private:
#ifdef XJF_JSON
	void *ToJsonObject(const XJF* pF = NULL);
	static const XJF* FromJsonObject(void *pJsonObject, const string &strNameArg = "");
#endif
#ifdef XJF_TUXEDO
	int FObjectToFML(void* pFMLData, const XJF* pF = NULL);
#endif
	static const XJF* FromBuf(const char *pBuf,const XJT32U &nLen);
	struct STTest {
	    uint32_t val1;
	    uint32_t val2;
	};
	union UNITest {
		uint64_t val;
	    struct STTest st;
	};
	static uint64_t conv_htonll(uint64_t v);
	static uint64_t conv_ntohll(uint64_t v);
protected:
	string m_strName;
	vector<string> m_veValue;
	enum XJF_TYPE m_nType;

	XJF *		m_pParent;
	XJF *		m_pFirstChild;
	XJF *		m_pLastChild;
	XJF *		m_pPrev;
	XJF *		m_pNext;

	static int 		m_nERRNO;
};
class XJFObject : public XJF {
public:
protected:
	XJFObject(const string &strName);
public:

private:

};
class XJFArray : public XJF {
public:
protected:
	XJFArray(const string &strName);
public:

private:
};
class XJFShort : public XJF {
public:
protected:
	XJFShort(const string &strName, const unsigned short &sValue=0);
public:

	int GetValue(unsigned short &sValue,const XJT32U &nIndex = 0);
	int SetValue(const unsigned short &sValue=0,const XJT32U &nIndex = 0);
private:

};
class XJFLong: public XJF {
public:
protected:
	XJFLong(const string &strName, const XJT32U &nValue=0);
public:

	int GetValue(XJT32U &nValue,const XJT32U &nIndex = 0);
	int SetValue(const XJT32U &nValue=0,const XJT32U &nIndex = 0);
private:

};
class XJFChar: public XJF {
public:
protected:
	XJFChar(const string &strName, const unsigned char &chValue = 0);
public:

	int GetValue(unsigned char &chValue,const XJT32U &nIndex = 0);
	int SetValue(const unsigned char &chValue=0,const XJT32U &nIndex = 0);
private:
};
class XJFFloat: public XJF {
public:
protected:
	XJFFloat(const string &strName, const float &fValue = 0.00);
public:

	int GetValue(float &fValue,const XJT32U &nIndex = 0);
	int SetValue(const float &fValue = 0.00,const XJT32U &nIndex = 0);
private:
};

class XJFDouble: public XJF {
public:
protected:
	XJFDouble(const string &strName, const double &dValue = 0.00);
public:

	int GetValue(double &dValue,const XJT32U &nIndex = 0);
	int SetValue(const double &dValue = 0.00,const XJT32U &nIndex = 0);
private:
};

class XJFString: public XJF {
public:
protected:
	XJFString(const string &strName, const string &strValue);
public:

	int GetValue(string &strValue,const XJT32U &nIndex = 0);
	int SetValue(const string &strValue,const XJT32U &nIndex = 0);
private:
};

class XJFCarray: public XJF {
public:
protected:
	XJFCarray(const string &strName, const char* pValue, const XJT32U &nLen);
public:

	int GetValue(char* pValue, XJT32U &nLen,const XJT32U &nIndex = 0);
	int SetValue(const char* pValue, const XJT32U &nLen,const XJT32U &nIndex = 0);
private:
};
class XJFPTR: public XJF {
public:
protected:
	XJFPTR(const string &strName, const void* pValue);
public:

	int GetValue(void** ppValue,const XJT32U &nIndex = 0);
	int SetValue(const void* pValue,const XJT32U &nIndex = 0);
private:
};


} /* namespace XJUtilClass */
#endif /* XJF_H_ */
